package top.ninwoo.utils.util.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import top.ninwoo.utils.entity.BridgePort;
import top.ninwoo.utils.entity.Ovs;
import top.ninwoo.utils.entity.OvsBridge;
import top.ninwoo.utils.util.LinuxCtlUtils;
import top.ninwoo.utils.util.OvsUtils;
import top.ninwoo.utils.util.Utils;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author joliu
 * @Description
 * @Date　Create in 下午9:29 2019/10/20
 */
@Utils
public class OvsUtilsImpl implements OvsUtils {
    private final Logger LOG = LoggerFactory.getLogger(OvsUtilsImpl.class);
    private final AtomicInteger atomicInteger = new AtomicInteger(0);
    @Autowired
    LinuxCtlUtils linuxCtlUtils;
    @Value("${cnf.passwd}")
    private String passwd;

    @Override
    public boolean isInstall() {
        // 可能会遇到权限问题
        String s = linuxCtlUtils.runCmd("echo '" + passwd + "' | sudo -S ovs-vsctl --version");
        if(s.contains("Error")) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public Ovs showDetails() {
        String res = linuxCtlUtils.runCmd("echo '" + passwd + "' | sudo -S ovs-vsctl show");

        Ovs ovs = parseOvsString(res);
        return ovs;
    }

    /**
     * 将返回的字符串转换为Ovs数据结构
     * @param ovsString
     * @return
     */
    @Override
    public Ovs parseOvsString(String ovsString) {
        if(ovsString == null || "".equals(ovsString)) {
            throw new RuntimeException("ovs String cannot be null or empty!");
        }
        String[] results = ovsString.split("\n");
        if(results.length < 2) {
            throw new RuntimeException("Illegal ovs Result!");
        }
        Ovs ovs = new Ovs();
        String ovsId = results[0].substring(0,results[0].length()-1);
        ovs.setId(ovsId);
        String ovsVersion = getValueInString(results[results.length - 1]);
        ovs.setOvsVersion(ovsVersion);

        int i = 0;
        OvsBridge bridge = null;
        BridgePort port = null;
        List<BridgePort> ports = new ArrayList<>();
        List<OvsBridge> bridges = new ArrayList<>();
        while(i < results.length) {
            // 创建Bridge
            if(results[i].contains("Bridge")) {
                port = null;
                ports.clear();
                if(bridge != null) {
                    // 放入到数组中
                    bridges.add(bridge);
                }
                String bridgeId = getValueInString(results[i]);
                bridge = new OvsBridge();
                bridge.setBridgeId(bridgeId);
            }
            else if(results[i].contains("Port")) {
                if(port != null) {
                    ports.add(port);
                }
                String portId = getValueInString(results[i]);
                port = new BridgePort();
                port.setPortId(portId.replace("\"", ""));
            }
            else if(results[i].contains("Interface")) {
                if(port == null) {
                    throw new RuntimeException("Cannot find Port");
                }
                String interfaceId = getValueInString(results[i]);
                port.setInterfaceId(interfaceId);
            }
            else if(results[i].contains("Error")) {
                if(port == null) {
                    throw new RuntimeException("Cannot find Port");
                }
                String error = getValueInString(results[i]);
                port.setError(error);
            } else if(results[i].contains("ovs_version")) {
                if(port != null) {
                    ports.add(port);
                    bridge.setPorts(ports);
                    bridges.add(bridge);
                }
                ovs.setBridges(bridges);
            }
            i++;
        }

        return ovs;
    }

    @Override
    public String getValueInString(String input) {
        String value = input.trim().split(" ")[1];
        value = value.replaceAll("\"", "");
        return value;
    }

    @Override
    public void addBridge(String name) {
        String cmd = "echo '" + passwd + "' | sudo -S ovs-vsctl add-br " + name;
        String res = linuxCtlUtils.runCmd(cmd);
        if(res.contains("Error")) {
            throw new RuntimeException("linux bridge has existed!");
        }
    }

    @Override
    public void setBridgeProtocol(String bridgeName, String protocol) {
        String cmd = "echo '" + passwd + "' | sudo -S ovs-vsctl set bridge " + bridgeName + " protocols=" + protocol;
        String res = linuxCtlUtils.runCmd(cmd);
        if(res.contains("Error")) {
            throw new RuntimeException(res);
        }
    }

    @Override
    public void setController(String bridgeName, String host, int port) {
        String cmd = "echo '" + passwd + "' | sudo -S ovs-vsctl set-controller " + bridgeName + " tcp:" + host + ":" + port;
        String res = linuxCtlUtils.runCmd(cmd);
        if(res.contains("Error")) {
            throw new RuntimeException(res);
        }
    }

    @Override
    public void delBridge(String name) {
        String cmd = "echo '" + passwd + "' | sudo -S ovs-vsctl del-br " + name;
        LOG.info("删除网桥[{}]", name);
        String res = linuxCtlUtils.runCmd(cmd);
        if(res.contains("Error")) {
            LOG.warn("bridge[{}] not found!", name);
        }
    }

    /**
     * 添加一个新的端口
     * @param bridgeName
     * @param port
     * @return
     */
    @Override
    public boolean addBridgePort(String bridgeName, String port) {
        String cmd = "echo '" + passwd + "' | sudo -S ovs-vsctl add-port " + bridgeName + " " + port;
        String res = linuxCtlUtils.runCmd(cmd);
        LOG.info("为Bridge：{} 添加Port：{}", bridgeName, port);
        if(!"".equals(res)) {
            LOG.warn( "AddBridgePort:" + "[" + bridgeName + "," + port + "]" + res);
            return false;
        }
        return true;
    }

    @Override
    public boolean delBridgePort(String bridgeName, String port) {
        String cmd = "echo '" + passwd + "' | sudo -S ovs-vsctl del-port " + bridgeName + " " + port;
        LOG.info("删除Bridge:{} Port:{}", bridgeName, port);
        String res = linuxCtlUtils.runCmd(cmd);
        if(!"".equals(res)) {
            LOG.warn(bridgeName + ":" + port + "[" + res + "]");
            return false;
        }
        return true;
    }

    /**
     * 创建一对虚拟网卡，输入的两个网桥名字作为创建网桥的辅助工具
     * @param br1
     * @param br2
     * @return
     */
    @Override
    public String[] createVethPair(String br1, String br2) {
        String veth1 = br1 + "_" + br2;
        String veth2 = br2 + "_" + br1;
        String cmd = "echo '" + passwd + "' | sudo -S ip link add " + veth1 + " type veth peer name " + veth2;
        LOG.info("创建虚拟网卡对[{},{}]", veth1, veth2);
        String res = linuxCtlUtils.runCmd(cmd);
        if(!"".equals(res)) {
            LOG.warn("createVethPair:[" + br1 + "," + br2 + "]:" + res);
        }
        return new String[]{veth1, veth2};
    }

    /**
     * 删除veth对
     * @param veths
     * @return
     */
    @Override
    public boolean delVethPort(String[] veths) {
        String veth1 = veths[0];
        String veth2 = veths[1];
        String cmd = "echo '" + passwd + "' | sudo -S ip link del " + veth1 + " type veth peer name " + veth2;
        LOG.info("删除虚拟网卡对[{},{}]", veth1, veth2);
        String res = linuxCtlUtils.runCmd(cmd);
        if(!"".equals(res)) {
            LOG.warn("delVethPair:[" + veth1 + "," + veth2 + "]:" + res);
            return false;
        }

        return true;
    }

    /**
     * 启动虚拟网卡
     * @param port
     * @return
     */
    @Override
    public boolean enableLinuxPort(String port) {
        String cmd = "echo '" + passwd + "' | sudo -S ifconfig " + port + " up";
        LOG.info("启动Linux端口：{}",port);
        String res = linuxCtlUtils.runCmd(cmd);
        if(!"".equals(res)) {
            LOG.warn("EnbaleLinuxPort:" + "[" + port + "]:" + port);
            return false;
        }
        return true;
    }

    /**
     * 启动网卡
     * @param ports
     * @return
     */
    @Override
    public boolean enableLinuxPort(String[] ports) {
        boolean result = true;
        for (String port : ports) {
            if (!enableLinuxPort(port)) {
                result = false;
            }
        }
        return result;
    }

    /**
     * 设置vxlan
     * @param bridgeName
     * @param remoteIp
     * @return
     */
    @Override
    public boolean setVxlan(String bridgeName, String remoteIp) {
        // TODO: bug
        int id = atomicInteger.getAndIncrement();
        String cmd = "echo '" + passwd + "' | sudo -S ovs-vsctl add-port " + bridgeName
                + " vxlan" + id + " -- set interface vxlan" + id + " type=vxlan options:remote_ip=" + remoteIp;
        System.out.println(cmd);
        LOG.info("设置VXLAN[bridgeName:{},remoteIP:{},{}]", bridgeName, remoteIp,cmd);
        String res = linuxCtlUtils.runCmd(cmd);
        if(!"".equals(res)) {
            LOG.warn("setVxlan:" + "[" + bridgeName + "]:" + res);
            return false;
        }
        return true;
    }
}
